﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Twitter;
using FriendsNearby.Services;
using System.ComponentModel.Design;
using FriendsNearby.Services.Facebook;
using InSTEDD.Labs.Geo;
using InSTEDD.Labs.Geo.Locators;
using InSTEDD.Labs.Geo.GeoCoding;
using InSTEDD.Labs.Geo.GeoCoding.Google;
using System.Configuration;
using Facebook.Web.Configuration;
using Facebook.Desktop;
using Facebook.Service.Core;

namespace FriendsNearbyBot
{
	internal class UpdateLocationProcessor : IMessageProcessor
	{
        IServiceProvider services;
        IMessageBuilder messageBuilder;
		Random random = new Random();
		int topIndex = int.Parse(Properties.Resources.LocationUpdateTopIndex);
        static CountryLocator countries = CountryLocator.FromFile("country_borders\\Country_Borders.txt");

		public UpdateLocationProcessor()
            : this(new FriendsNearbyFacade())
		{
		}

        public UpdateLocationProcessor(IServiceProvider services)
            : this(services, new PlainTextMessageBuilder())
        {
        }

        public UpdateLocationProcessor(IServiceProvider services, IMessageBuilder messageBuilder)
		{
			this.services = services;
            this.messageBuilder = messageBuilder;
		}

        public bool CanProcess(Message message)
        {
            string msg = message.Text;

            return msg.StartsWith("at ") || msg.StartsWith("at\t");
        }

        public RunNextProcessor Process(IBotClient client, Message message)
        {
            
            string command = message.Text;

            if (command.StartsWith("at ") || command.StartsWith("at\t"))
            {
                command = command.Substring(2);
                command = command.Trim();

                string facebookId = services.GetService<IUsersService>().
                    GetFacebookUserIdFromTwitter(message.Sender.ScreenName);

                messageBuilder.Clear();

                if (facebookId == null)
                {
                    // Warn the user via SMS that the mapping has not been established.                    
                    messageBuilder.AppendFragment(String.Format(Properties.Resources.TwitterNotMapped, message.Sender.ScreenName));
                    client.SendMessages(message.Sender.ScreenName, messageBuilder.GetMessages(), message, this.GetType().Name);                    
                }
                else
                {

                    // The other commands have to come first, as the location might have a straight address.
                    // if "friends"
                    // elseif "1|2|3"

                    // If it's none of the other commands, try to do an update location.
                    bool ack = !ShouldNotAcknowledge(ref command);

                    LatLong location = ParseLocation(command);
                    if (location == null)
                    {
                        // TODO remove this message and forward to a default MessageNotInterpretedProcessor
                        // Warn the user via SMS that we couldn't convert his values.
                        messageBuilder.AppendFragment(string.Format(Properties.Resources.InvalidLocation, command));
                        client.SendMessages(message.Sender.ScreenName, messageBuilder.GetMessages(), message, this.GetType().Name);
                    }
                    else
                    {
                        // TODO: Add try/catch. 
                        services.GetService<ILocationService>().SetCurrentLocation(
                            facebookId, location);

                        Country country = countries.GetCountryForPoint(location);
                        if (country == null)
                        {
                            messageBuilder.AppendFragment(Properties.Resources.LocationNotLand);
                            client.SendMessages(message.Sender.ScreenName, messageBuilder.GetMessages(), message, this.GetType().Name);
                        }
                        else if (ack)
                        {
                            // Acknowledge the user that we performed the change.
                            int msgId = random.Next(0, topIndex + 1);

                            //string displayName = services.GetService<ISocialNetworkService>().GetUserDisplayName(facebookId);
                            messageBuilder.AppendFragment(String.Format(Properties.Resources.ResourceManager.GetString("LocationUpdated" + msgId), 
                                country.Name));
                            client.SendMessages(message.Sender.ScreenName, messageBuilder.GetMessages(), message, this.GetType().Name);
                        }
                    }
                }

                BotProcessor.MessageProcessed(client, message);
                return RunNextProcessor.No;
            }
            else
                return RunNextProcessor.Yes;



        }

		private static LatLong ParseLocation(string command)
		{
			LatLong location;
			if (command.Contains('*'))
			{
				LatLong.TryParse(command, '*', out location);
			}
			else
			{
				IGeoCoder coder = new GoogleGeoCoder();
                coder.Initialize(ConfigurationManager.AppSettings["GoogleMapsAPIKey"]);

				// TODO: might hit the limit.
				location = coder.GetLatLongFromPostalAddress(command);
			}
			return location;
		}

		private static bool ShouldNotAcknowledge(ref string command)
		{
			bool nack = false;
			if (command.Contains("nack"))
			{
				command = command.Replace("nack", "").Trim();
				nack = true;
			}
			return nack;
		}
	}
}
